10 * 1024 * 1024) { $error = "File size too large. Maximum allowed size is 10MB."; } else { try { $inputFileName = $_FILES['excel_file']['tmp_name']; $questions_data = parseXLSXFile($inputFileName); if (empty($questions_data)) { $error = "No valid questions found in the file or unable to parse the file."; throw new Exception($error); } $pdo->beginTransaction(); $pdo->exec("SET NAMES utf8mb4"); $questions_added = 0; $skipped_rows = 0; foreach ($questions_data as $row_index => $row) { // Skip empty rows if (empty(trim($row['question_text']))) { $skipped_rows++; continue; } $correct_answer = strtoupper(trim($row['correct_answer'])); if (!in_array($correct_answer, ['A', 'B', 'C', 'D'])) { $error = "Invalid correct answer '{$correct_answer}' in row " . ($row_index + 2) . ". Must be A, B, C, or D."; $pdo->rollBack(); break; } $marks = intval($row['marks']); if ($marks < 1) { $marks = 1; } // Clean text data $clean_question_text = cleanText($row['question_text']); $clean_option_a = cleanText($row['option_a']); $clean_option_b = cleanText($row['option_b']); $clean_option_c = cleanText($row['option_c']); $clean_option_d = cleanText($row['option_d']); // Insert question $stmt = $pdo->prepare("INSERT INTO questions (exam_id, subject_id, question_text, option_a, option_b, option_c, option_d, correct_answer, marks) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"); $stmt->execute([ $exam_id, $subject_id, $clean_question_text, $clean_option_a, $clean_option_b, $clean_option_c, $clean_option_d, $correct_answer, $marks ]); $questions_added++; } if (empty($error)) { $stmt = $pdo->prepare("UPDATE exams SET total_questions = (SELECT COUNT(*) FROM questions WHERE exam_id = ?) WHERE id = ?"); $stmt->execute([$exam_id, $exam_id]); $pdo->commit(); $success = "Successfully uploaded {$questions_added} questions for the selected subject!" . ($skipped_rows > 0 ? " {$skipped_rows} empty rows were skipped." : ""); } } catch (Exception $e) { $pdo->rollBack(); $error = "Error uploading file: " . $e->getMessage(); } } } } /** * Parse XLSX file manually using ZIP and XML */ function parseXLSXFile($filename) { $questions = []; // Check if ZIP extension is available if (!class_exists('ZipArchive')) { throw new Exception("ZIP extension is required for XLSX file processing. Please enable php_zip extension in your PHP configuration."); } $temp_dir = sys_get_temp_dir() . '/xlsx_extract_' . uniqid(); if (!mkdir($temp_dir, 0755, true)) { throw new Exception("Could not create temporary directory for XLSX extraction."); } $zip = new ZipArchive(); if ($zip->open($filename) !== TRUE) { deleteDirectory($temp_dir); throw new Exception("Could not open XLSX file. File may be corrupted or not a valid XLSX file."); } try { // Extract to temporary directory $zip->extractTo($temp_dir); $zip->close(); // Parse shared strings $sharedStrings = parseSharedStrings($temp_dir); // Parse worksheet data $questions = parseWorksheet($temp_dir, $sharedStrings); } catch (Exception $e) { deleteDirectory($temp_dir); throw $e; } deleteDirectory($temp_dir); return $questions; } /** * Parse shared strings from XLSX */ function parseSharedStrings($temp_dir) { $sharedStrings = []; $sharedStringsFile = $temp_dir . '/xl/sharedStrings.xml'; if (!file_exists($sharedStringsFile)) { return $sharedStrings; } $content = file_get_contents($sharedStringsFile); // Extract all text elements from shared strings preg_match_all('/]*>(.*?)<\/t>/s', $content, $matches); foreach ($matches[1] as $index => $text) { $sharedStrings[$index] = html_entity_decode($text, ENT_QUOTES | ENT_XML1, 'UTF-8'); } return $sharedStrings; } /** * Parse worksheet data - UPDATED FOR YOUR FILE FORMAT */ function parseWorksheet($temp_dir, $sharedStrings) { $questions = []; $sheetFile = $temp_dir . '/xl/worksheets/sheet1.xml'; if (!file_exists($sheetFile)) { throw new Exception("Could not find worksheet data in the XLSX file."); } $content = file_get_contents($sheetFile); // Extract all rows preg_match_all('/]*>(.*?)<\/row>/s', $content, $rowMatches); foreach ($rowMatches[1] as $rowIndex => $rowContent) { if ($rowIndex == 0) continue; // Skip header row $rowData = parseRowData($rowContent, $sharedStrings); // UPDATED: Match your Excel file structure // Column A: No (skip) // Column B: Question // Column C: Option A // Column D: Option B // Column E: Option C // Column F: Option D // Column G: Answer if (count($rowData) >= 7) { $question = [ 'question_text' => $rowData['B'] ?? '', 'option_a' => $rowData['C'] ?? '', 'option_b' => $rowData['D'] ?? '', 'option_c' => $rowData['E'] ?? '', 'option_d' => $rowData['F'] ?? '', 'correct_answer' => $rowData['G'] ?? '', 'marks' => 1 // Default marks since your file doesn't have marks column ]; // Only add if we have a question if (!empty(trim($question['question_text']))) { $questions[] = $question; } } } return $questions; } /** * Parse individual row data */ function parseRowData($rowContent, $sharedStrings) { $rowData = []; // Extract all cells in the row with their column references preg_match_all('/]*r="([A-Z])(\d+)"[^>]*>(.*?)<\/c>/s', $rowContent, $cellMatches, PREG_SET_ORDER); foreach ($cellMatches as $cellMatch) { $column = $cellMatch[1]; // Column letter (A, B, C, etc.) $cellContent = $cellMatch[3]; // Extract cell value preg_match('/]*>(.*?)<\/v>/s', $cellContent, $valueMatch); if (!isset($valueMatch[1])) { $rowData[$column] = ''; continue; } $cellValue = trim($valueMatch[1]); // Check if cell uses shared string if (strpos($cellMatch[0], 't="s"') !== false) { // Value is an index into shared strings $stringIndex = intval($cellValue); $rowData[$column] = $sharedStrings[$stringIndex] ?? ''; } else { // Direct value $rowData[$column] = $cellValue; } } return $rowData; } /** * Clean text data for UTF-8 encoding */ function cleanText($text) { if (empty($text)) return ''; $clean = trim($text); $clean = preg_replace('/\xE2\x88\x92/', '-', $clean); // Replace minus sign $clean = html_entity_decode($clean, ENT_QUOTES | ENT_XML1, 'UTF-8'); $clean = mb_convert_encoding($clean, 'UTF-8', 'UTF-8'); return $clean; } /** * Helper function to delete directory recursively */ function deleteDirectory($dir) { if (!file_exists($dir)) return true; if (!is_dir($dir)) return unlink($dir); foreach (scandir($dir) as $item) { if ($item == '.' || $item == '..') continue; if (!deleteDirectory($dir . DIRECTORY_SEPARATOR . $item)) { return false; } } return rmdir($dir); } // Get exams for dropdown $stmt = $pdo->prepare("SELECT * FROM exams ORDER BY year DESC, name"); $stmt->execute(); $exams = $stmt->fetchAll(PDO::FETCH_ASSOC); // Get subjects for dropdown $stmt = $pdo->prepare("SELECT * FROM subjects ORDER BY name"); $stmt->execute(); $subjects = $stmt->fetchAll(PDO::FETCH_ASSOC); ?> Upload Questions - Admin

Upload Questions

Bulk upload questions from Excel files (.xlsx)

Warning: ZIP extension is not enabled on your server. Please contact your hosting provider to enable the php_zip extension.

Upload Excel File

📤

Drag & Drop your Excel file here

or

Supported format: .xlsx only (Max: 10MB)
❌ Upload disabled: ZIP extension required

Excel File Format (Updated)

Your Excel file should have the following columns in order (starting from row 2):

Column Content Required Example Notes
A Question Number Optional 1 Auto-numbering, can be omitted
B Question Text Required What is the capital of Nigeria? Main question content
C Option A Required Lagos First multiple choice option
D Option B Required Abuja Second multiple choice option
E Option C Required Kano Third multiple choice option
F Option D Required Port Harcourt Fourth multiple choice option
G Correct Answer Required B Must be A, B, C, or D (case insensitive)

Note: All questions will be assigned 1 mark by default

📥 Download Template